package com.example.websocket.excel.util;

import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.IOException;
import java.math.BigDecimal;
import java.text.NumberFormat;
import java.text.ParseException;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;


/**
 * 处理数据格式化等操作
 * @author Gaojt
 *
 */
public class DataUtils {
	/**
	 * 数据合计
	 * @param values
	 * @return
	 */
	@SuppressWarnings("unchecked")
	@SafeVarargs
	public static<T> T sums(T... values) {
		return Optional.ofNullable(values)
				.map(Arrays::stream)
				.map(stream -> stream
						.filter(Objects::nonNull)
						.reduce((v1, v2) -> {
							if (v1.getClass().equals(v2.getClass())) {//相同类型
								if (v1 instanceof Double) {
									return (T)new Double(((Double)v1).doubleValue() + ((Double)v2).doubleValue());
								} else if (v1 instanceof Float) {
									return (T)new Float(((Float)v1).floatValue() + ((Float)v2).floatValue());
								} else if (v1 instanceof Long) {
									return (T)new Long(((Long)v1).longValue() + ((Long)v2).longValue());
								} else if (v1 instanceof Integer) {
									return (T)new Integer(((Integer)v1).intValue() + ((Integer)v2).intValue());
								} else if (v1 instanceof Short) {
									return (T)new Short((short)(((Short)v1).shortValue() + ((Short)v2).shortValue()));
								} else if (v1 instanceof Byte) {
									return (T)new Byte((byte)(((Byte)v1).byteValue() + ((Byte)v2).byteValue()));
								} else if (v1 instanceof BigDecimal) {
									return (T)((BigDecimal)v1).add((BigDecimal)v2);
								}
							} else {
								throw new IllegalArgumentException("本方法调用的数据必须为相同类型");
							}
							return v1;
						})
						.orElse(null)
					)
				.orElse(null);
	}
	/**
	 * 数据相减
	 * @param values
	 * @return
	 */
	@SuppressWarnings("unchecked")
	@SafeVarargs
	public static<T> T subtracts(T... values) {
		return Optional.ofNullable(values)
				.map(Arrays::stream)
				.map(stream -> stream
						.filter(Objects::nonNull)
						.reduce((v1, v2) -> {
							if (v1.getClass().equals(v2.getClass())) {//相同类型
								if (v1 instanceof Double) {
									return (T)new Double(((Double)v1).doubleValue() - ((Double)v2).doubleValue());
								} else if (v1 instanceof Float) {
									return (T)new Float(((Float)v1).floatValue() - ((Float)v2).floatValue());
								} else if (v1 instanceof Long) {
									return (T)new Long(((Long)v1).longValue() - ((Long)v2).longValue());
								} else if (v1 instanceof Integer) {
									return (T)new Integer(((Integer)v1).intValue() - ((Integer)v2).intValue());
								} else if (v1 instanceof Short) {
									return (T)new Short((short)(((Short)v1).shortValue() - ((Short)v2).shortValue()));
								} else if (v1 instanceof Byte) {
									return (T)new Byte((byte)(((Byte)v1).byteValue() - ((Byte)v2).byteValue()));
								} else if (v1 instanceof BigDecimal) {
									return (T)((BigDecimal)v1).subtract((BigDecimal)v2);
								}
							} else {
								throw new IllegalArgumentException("本方法调用的数据必须为相同类型");
							}
							return v1;
						})
						.orElse(null)
					)
				.orElse(null);
	}
	/**
	 * 判断两个数值是否相等
	 * @param source
	 * @param target
	 * @return
	 */
	public static boolean composeTo(Number source, Number target) {
		if (source == null) {
			return target == null;
		}
		if (target == null) {
			return source == null;
		}
		return source.doubleValue() == target.doubleValue();
	}
	/**
	 * 连减计算
	 * @param arrays
	 * @return
	 */
	public static double reduce(Double... array) {
		if(array == null || array.length == 0)
			return 0d;
		double sum = Arrays.stream(array)
			.map(e -> e == null ? 0d : e)
			.mapToDouble(Double::doubleValue)
			.reduce((e1, e2) -> e1 - e2)
			.orElse(0d);
		return sum;
	}
	/**
	 * 合计数据
	 * @param arrays
	 * @return
	 */
	public static double sum(Number...arrays) {
		return Arrays.stream(arrays)
			.filter(d -> d != null)
			.mapToDouble(Number::doubleValue)
			.sum();
	}
	/**
	 * 合计数据
	 * @param arrays
	 * @return
	 */
	public static BigDecimal sum(BigDecimal...arrays) {
		return Arrays.stream(arrays)
			.filter(d -> d != null)
			.reduce(BigDecimal::add)
			.orElse(BigDecimal.ZERO);
	}
	/**
	 * 判断对象是否为非空，与isEmpty方法相反。
	 * @param value
	 * @return
	 */
	public static boolean nonEmpty(Object value) {
		return !isEmpty(value);
	}
	/**
	 * 判断对象是否为空，规则：null、数组或者容器长度为0或者存储元素全部为null、String长度为0都返回true，其他返回false
	 * @param value
	 * @return
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public static boolean isEmpty(Object value) {
		if (value == null)
			return true;
		if (value.getClass().isArray()) {
			Object[] array = (Object[]) value;
			long count = Arrays.stream(array)
				.filter(Objects::nonNull)
				.count();
			return count == 0;
		}
		if (value instanceof Collection) {
			Collection c = (Collection)value;
			long count = c.stream()
					.filter(Objects::nonNull)
					.count();
			return count == 0;
		}
		if (value instanceof Map) {
			Map m = (Map)value;
			return m.size() == 0;
		}
		return value.toString().trim().length() == 0;
	}
	/**
	 * 判断对象是否为真
	 * Null：false
	 * Boolean类型：返回true或者false
	 * Number类型 ：<0 false， > 0 true
	 * String类型："false"或者"负数" 或者""返回false，其他返回true
	 * Object类型：根据toString()判断
	 * @param value
	 * @return
	 */
	public static boolean isTrue(Object value) {
		if(value == null)
			return false;
		if(value instanceof Boolean) {
			return ((Boolean)value).booleanValue();
		}
		if(value instanceof Number) {
			return ((Number)value).longValue() >= 0;
		}
		String str = value.toString().trim();
		if(str.length() == 0 || str.equalsIgnoreCase("false"))
			return false;
		try {
			Double d = new Double(str);
			return d >= 0;
		} catch (NumberFormatException e) {
			return true;
		}
	}
	/**
	 * 将对象数据转换成int
	 * @param obj 需转换的数据
	 * @return int 数据；如果数据不能转换，则返回0
	 */
	public static Long toLong(Object obj){
		if(obj == null){
			return null;
		}
		if(obj instanceof Number){
			Number number = (Number)obj;
			return number.longValue();
		}
		Long rs = null;
		try {
			rs = new Long(obj.toString().trim());
		} catch (NumberFormatException e) {
		}
		return rs;
	}
	/**
	 * 转换为float类型数据
	 * @param v
	 * @return
	 */
	public static Float toFloat(Object v) {
		Double d = toDouble(v);
		return d == null ? null : d.floatValue();
	}
	/**
	 * 转换为Double类型数据
	 * @param v
	 * @return
	 */
	public static Double toDouble(Object v){
		if(v == null)
			return null;
		if(v instanceof Double) {
			return (Double)v;
		}else if(v instanceof Number){
			Number n = (Number)v;
			return n.doubleValue();
		}else if(v instanceof String){
			Pattern p = Pattern.compile("([^%]+)%");//百分比
			Matcher m = p.matcher((String)v);
			if(m.matches()) {
				String num = m.group(1);
				try {
					return Double.parseDouble(num) / 100;
				} catch (NumberFormatException e) {
					try {
						NumberFormat n = NumberFormat.getInstance();
						return n.parse(num).doubleValue();
					} catch (ParseException e1) {
						return null;
					}
				}
			}
		}
		try {
			NumberFormat n = NumberFormat.getInstance();
			return n.parse(v.toString()).doubleValue();
		} catch (NumberFormatException e) {
			return null;
		} catch (ParseException e) {
			return null;
		}
	}
	/**
	 * 转换小数
	 * @param v
	 * @return
	 */
	public static double toZeroDouble(Object v){
		if(v == null){
			return 0;
		}else if(v instanceof Number){
			return ((Number)v).doubleValue();
		}else if(v instanceof BigDecimal){
			return ((BigDecimal)v).doubleValue();
		}else{
			try {
				return Double.parseDouble(v.toString());
			} catch (NumberFormatException e) {
				return 0;
			}
		}
	}
	/**
	 * 将浮点数字转换为保留两位小数数据
	 * @param v
	 * @return
	 */
	public static double toLimDouble(double v){
		NumberFormat f = NumberFormat.getInstance();
		f.setMaximumFractionDigits(2);
		String string = f.format(v);
		try {
			return f.parse(string).doubleValue();
		} catch (ParseException e) {
			return 0d;
		}
	}
	/**
	 * 将对象数据转换成int
	 * @param obj 需转换的数据
	 * @return int 数据；如果数据不能转换，则返回0
	 */
	public static Integer toInteger(Object obj){
		if(obj == null){
			return null;
		}
		if(obj instanceof Number){
			Number number = (Number)obj;
			return number.intValue();
		}
		Integer rs = null;
		try {
			rs = new Integer(obj.toString().trim());
		} catch (NumberFormatException e) {
		}
		return rs;
	}
	/**
	 * 將字符串转换为boolean类型
	 * @param string
	 * @return
	 * @author 高建涛 2010-6-22下午03:53:59
	 */
	public static boolean toBoolean(String string){
		boolean b = false;
		if(string != null)
			b = Boolean.parseBoolean(string);
		return b;
	}
	/**
	 * 将字符串转换成Integer类型
	 * @param string 字符串
	 * @return 整形字符
	 */
	public static Integer toInteger(String string){
		Integer integer = null;
		try {
			if(string != null)
				integer = new Integer(string.trim());
		} catch (NumberFormatException e) {
		}
		return integer;
	}
	/**
	 * 将字符串转换成BigDecimal类型
	 * @param string
	 * @return
	 */
	public static BigDecimal toBigDecimal(Object data){
		if(data == null)
			return null;
		if(data instanceof Double) {
			return new BigDecimal((Double)data);
		}else if(data instanceof BigDecimal){
			return (BigDecimal)data;
		}else if(data instanceof Number){
			Number n = (Number)data;
			return new BigDecimal(n.doubleValue());
		}else {
			Double d = toDouble(data.toString());
			if(d == null)
				return null;
			return new BigDecimal(d);
		}
	}
	/**
	 * 将字符串转换成BigDecimal类型，保留小数点位2位数
	 * @param string
	 * @return
	 */
	public static BigDecimal toLimBigDecimal(Object data){
		BigDecimal v = toBigDecimal(data);
		if(v != null)
			return v.setScale(2, BigDecimal.ROUND_HALF_UP);
		return v;
	}
	/**
	 * 将字符串转化为double类型
	 * @param currency
	 * @return
	 */
	public static double parseCurrency(String currency){
		NumberFormat f = NumberFormat.getNumberInstance();
		try {
			return f.parse(currency).doubleValue();
		} catch (ParseException e) {
			return 0d;
		}
	}
	
	/**
	 * 将javabean对象转换为json字符串
	 * @param obj
	 * @return
	 */
	public static String toJson(Object obj){
		ObjectMapper mapper = new ObjectMapper();
		// 为了使JSON视觉上的可读性，增加一行如下代码，注意，在生产中不需要这样，因为这样会增大Json的内容  
//        mapper.configure(SerializationFeature.INDENT_OUTPUT, true);  
        // 配置mapper忽略空属性  
        mapper.setSerializationInclusion(Include.NON_EMPTY);  
        // 默认情况，Jackson使用Java属性字段名称作为 Json的属性名称,也可以使用Jackson annotations(注解)改变Json属性名称  
        try {
			return mapper.writeValueAsString(obj);
		} catch (JsonProcessingException e) {
			return null;
		}
	}
	/**
	 * 将字符串转化为对应的javabean对象
	 * @param jsonString
	 * @param c
	 * @return
	 */
	public static <T> T parseJson(String jsonString, Class<T> c){
		ObjectMapper mapper = new ObjectMapper();
		//当反序列化json时，未知属性会引起的反序列化被打断，这里我们禁用未知属性打断反序列化功能，  
        //因为，例如json里有10个属性，而我们的bean中只定义了2个属性，其它8个属性将被忽略  
        mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);  
		try {
			return mapper.readValue(jsonString, c);
		} catch (JsonParseException e) {
			e.printStackTrace();
			return null;
		} catch (JsonMappingException e) {
			e.printStackTrace();
			return null;
		} catch (IOException e) {
			e.printStackTrace();
			return null;
		}
	}
	/**
	 * 将字符串转化为对应的javabean对象
	 * @param jsonString
	 * @param c
	 * @return
	 */
	public static Map<?, ?> parseJson(String jsonString){
		return DataUtils.parseJson(jsonString, Map.class);
	}
	/**
	 * 比较两个科目的前后顺序
	 * @param num1
	 * @param num2
	 * @return
	 */
	 public static boolean compareIndex(String num1, String num2) {
    	if(num1.length()>num2.length()){
    		num2 = num2+String.format("%1$0"+(num1.length()-num2.length())+"d",0);
    	} else if(num1.length()<num2.length()){
    		num1 = num1+String.format("%1$0"+(num2.length()-num1.length())+"d",0);
    	}
    	return Integer.parseInt(num1)>Integer.parseInt(num2)?true:false;
    }
	/**
	 * 判断两个对象是否相同
	 * @param obj1
	 * @param obj2
	 * @return
	 */
	public static boolean equals(Object obj1, Object obj2) {
		 if(obj1 == null) {
			 if(obj2 == null)
				 return true;
			 else
				 return false;
		 }else {
			 if(obj2 == null)
				 return false;
			 else
				 return obj1.equals(obj2);
		 }
	 }
	/**
	 * 从容器中取得唯一字段，如果容器为null或者元素为空，返回null
	 * @param l
	 * @return
	 */
	public static <T> T findFirst(Collection<T> l) {
		T t =  Optional.ofNullable(l)
			.flatMap(list -> list.stream().findFirst())
			.orElse(null);
		return t;
	}
	/**
	 * 对象值转换为url的param1=value1&param2=value2格式
	 * @param object
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static String toUrlParams(Object object) {
		return Optional.ofNullable(object)
			.map(BeanUtils::describe)
			.map(m -> m.entrySet().stream()
					.filter(Objects::nonNull)
					.filter(e -> DataUtils.nonEmpty(e.getValue()))
					.flatMap(e -> {
						if (e.getValue().getClass().isArray()) {
							return Optional.of(e.getValue())
									.map(Object[].class::cast)
									.map(Arrays::stream)
									.map(stream -> stream.filter(Objects::nonNull)
											.map(Object::toString)
											.map(e.getKey().concat("=")::concat))
									.orElse(null);
						} else if (e.getValue() instanceof Collection) {
							return Optional.of(e.getValue())
									.map(obj -> (Collection<Object>)obj)
									.map(Collection::stream)
									.map(stream -> stream
											.filter(Objects::nonNull)
											.map(Object::toString)
											.map(e.getKey().concat("=")::concat))
									.orElse(null);
						} else {
							return Collections.singletonList(e.getKey() + "=" + e.getValue()).stream();
						}
						
					})
					.filter(Objects::nonNull)
					.collect(Collectors.joining("&"))
			).orElse(null);
	}
}
